import {
  CanActivate,
  ExecutionContext,
  Injectable,
  ForbiddenException,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { HAS_PERMI } from 'src/decorators/auth.decorator';
import { CommonService } from 'src/modules/system/common/common.service';
import { DepartmentService } from 'src/modules/system/department/department.service';
import { MenuService } from 'src/modules/system/menu/menu.service';
import { UserDto } from 'src/modules/system/user/user.dto';
import { UserService } from 'src/modules/system/user/user.service';
import { handleTree } from 'src/utils/tools';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly commonService: CommonService,
    private readonly userService: UserService,
    private readonly departmentService: DepartmentService,
    private readonly menuService: MenuService,
  ) {}

  async canActivate(ctx: ExecutionContext): Promise<boolean> {
    const req = ctx.switchToHttp().getRequest();
    // 获取调用路由的权限标识
    const permissionStr = this.reflector.getAllAndOverride(HAS_PERMI, [
      ctx.getHandler(),
      ctx.getClass(),
    ]);
    if (!permissionStr) return true; // 无需权限标识

    const accessToken = req.get('Authorization');
    if (!accessToken) throw new ForbiddenException('请先登录');
    const baseUser: any = this.commonService.verifyToken(accessToken);
    if (!baseUser) {
      (req.session as any).userInfo = null;
      throw new UnauthorizedException('当前登录已过期，请重新登录');
    }
    const user: UserDto = await this.userService.getOne({
      where: {
        user_name: baseUser.user_name,
      },
      relations: ['roles', 'dept'],
    });

    let permissions: string[];
    // 是否超级管理员
    if (user.id === 1) {
      permissions = ['*:*:*'];
    } else {
      const roles = user.roles.map((item) => ({
        id: item.id,
      }));
      if (!roles || !roles.length) {
        throw new Error('没有查询到菜单');
      }
      // 获取权限标识菜单
      const menus = await this.menuService.getAll({
        where: {
          roles: roles,
          menu_type: 'F',
        },
      });
      permissions = menus.lists.map((item) => item.perms);
    }

    const detp = await this.departmentService.getAll({
      where: {
        is_delete: '0',
      },
      order: {
        sort: 'ASC',
      },
    });

    (req.session as any).userInfo = user;
    (req.session as any).permissions = permissions;
    (req.session as any).departmentsObj = handleTree(detp.lists);

    //* 代表 超管  拥有所有权
    if (permissions && permissions.includes('*:*:*')) {
      return true;
    }
    // 权限标识白名单
    const whiteLists = ['system:menu:userMenu', 'system:user:getInfo'];
    permissions = [...permissions, ...whiteLists];
    if (!permissions || !permissions.includes(permissionStr)) {
      throw new ForbiddenException('您无权限访问该接口');
    }
    return true;
  }
}
